package com.novunda.platform.common.utils;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.novunda.platform.common.context.SpringContextHolder;
import com.novunda.platform.common.security.Principal;
import com.novunda.platform.entities.Menu;
import com.novunda.platform.entities.Office;
import com.novunda.platform.entities.User;
import com.novunda.platform.entities.base.BaseEntity;
import com.novunda.platform.repositories.MenuRepository;
import com.novunda.platform.repositories.OfficeRepository;
import com.novunda.platform.repositories.UserRepository;
import com.novunda.platform.services.BaseService;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.UnavailableSecurityManagerException;
import org.apache.shiro.subject.Subject;
import org.hibernate.criterion.DetachedCriteria;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;

import java.util.List;
import java.util.Map;

/**
 * @author linfeng
 * @since 2016/8/29
 */
public final class UserUtils extends BaseService {

    public static final String CACHE_USER = "user";
    public static final String CACHE_MENU_LIST = "menuList";
    public static final String CACHE_HORIZANTAL_MENU_LIST = "horizantalMenuList";
    public static final String CACHE_OFFICE_LIST = "officeList";

    private static final UserRepository userRepository = SpringContextHolder.getBean("userRepository");
    private static final MenuRepository menuRepository = SpringContextHolder.getBean("menuRepository");
    private static final OfficeRepository officeRepository = SpringContextHolder.getBean("officeRepository");


    private UserUtils() {
    }

    /**
     * 获取当前用户
     *
     * @param isRefresh 是否获取数据库最新用户
     * @return 用户
     */
    public static User getUser(boolean isRefresh) {
        if (isRefresh) {
            removeCache(CACHE_USER);
        }
        return getUser();
    }

    /**
     * 获取当期用户
     *
     * @return 用户
     */
    public static User getUser() {
        User user = (User) getCache(CACHE_USER);
        if (user == null) {
            Principal principal = (Principal) SecurityUtils.getSubject().getPrincipal();
            if (principal != null) {
                user = userRepository.findOne(principal.getId());
                putCache(CACHE_USER, user);
            }
        }
        if (user == null) {
            user = new User();
            SecurityUtils.getSubject().logout();
        }
        return user;
    }

    /**
     * 获取当前用户所有的菜单列表
     *
     * @return 菜单列表 List<Menu>
     */
    public static List<Menu> getMenuList() {
        @SuppressWarnings("unchecked")
        List<Menu> menuList = (List<Menu>) getCache(CACHE_MENU_LIST);
        if (menuList == null || menuList.isEmpty()) {
            User user = getUser();
            if (user.isAdmin()) {
                menuList = menuRepository.findAllList();
            } else {
                menuList = menuRepository.findByUserId(user.getId());
            }
            putCache(CACHE_MENU_LIST, menuList);
        }
        return menuList;
    }

    public static List<Menu> getHorizantalMenu() {
        @SuppressWarnings("unchecked")
        List<Menu> menuList = (List<Menu>) getCache(CACHE_HORIZANTAL_MENU_LIST);
        if (menuList == null || menuList.isEmpty()) {
            menuList = getRootMenuList(getMenuList());
            putCache(CACHE_HORIZANTAL_MENU_LIST, menuList);
        }
        return menuList;
    }

    public static Menu getMenuById(Long id) {
        List<Menu> allMenus = getMenuList();
        for (Menu menu : allMenus) {
            if (menu.getId().equals(id)) {
                return menu;
            }
        }
        return null;
    }

    /**
     * 获取根菜单下面第一级菜单
     *
     * @param menus 所有的菜单列表
     * @return 第一级菜单集合
     */
    private static List<Menu> getRootMenuList(List<Menu> menus) {
        List<Menu> results = Lists.newArrayList();
        for (Menu e : menus) {
            if (e.getParent() != null && e.getParent().getId().equals(1L) && BaseEntity.SHOW.equals(e.getIsShow())) {
                List<Menu> childList = Lists.newArrayList();
            	for (Menu menu : menus) {
            		Menu parentMenu = menu.getParent();
            		if (null != parentMenu && parentMenu.equals(e)) {
            			childList.add(menu);
            		}
            	}
            	e.setChildList(childList);
            	results.add(e);
            }
        }
        return results;
    }

    /**
     * 获取部门信息列表
     *
     * @return 部门信息列表
     */
    public static List<Office> getOfficeList() {
        @SuppressWarnings("unchecked")
        List<Office> officeList = (List<Office>) getCache(CACHE_OFFICE_LIST);
        if (officeList == null || officeList.isEmpty()) {
            User user = getUser();
            DetachedCriteria dc = officeRepository.createDetachedCriteria();
            dc.add(dataScopeFilter(user, dc.getAlias(), ""));
            dc.add(Restrictions.eq("delFlag", BaseEntity.DEL_FLAG_NORMAL));
            dc.addOrder(Order.asc("code"));
            officeList = officeRepository.find(dc);
            putCache(CACHE_OFFICE_LIST, officeList);
        }
        return officeList;
    }

    /**
     * 获取缓存对象
     *
     * @param key 缓存key
     * @return 缓存对象
     */
    public static Object getCache(String key) {
        return getCache(key, null);
    }

    public static Object getCache(String key, Object defaultValue) {
        Object obj = getCacheMap().get(key);
        return obj == null ? defaultValue : obj;
    }

    public static void putCache(String key, Object value) {
        getCacheMap().put(key, value);
    }

    public static void removeCache(String key) {
        getCacheMap().remove(key);
    }

    public static Map<String, Object> getCacheMap() {
        Map<String, Object> map = Maps.newHashMap();
        try {
            Subject subject = SecurityUtils.getSubject();
            Principal principal = (Principal) subject.getPrincipal();
            return principal != null ? principal.getCacheMap() : map;
        } catch (UnavailableSecurityManagerException ignored) {
            return map;
        }
    }

}
